﻿using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.ServiceModel.DomainServices.Client;
using System.Windows;
using Agility.ViewModels;
using Agility.Web.Models.DomainModel;
using Moq;
using OneOfAKind.Toolbox.SilverlightTools.Testing;

namespace Agility.Testing.Silverlight.AppDriver
{
    public class RequirementsDriver
    {
        MyIdeasViewModel myIdeasVM;
        Mock<MockDomainClient> mockDomainClient;
        List<Entity> testData;
        bool modified;

        public RequirementsDriver()
        {
            this.testData = new List<Entity>();
            this.modified = false;
            this.mockDomainClient = new Mock<MockDomainClient>();
            this.mockDomainClient.Setup(dc => dc.Query(It.IsAny<EntityQuery>())).Returns(() => testData.AsQueryable());
            this.mockDomainClient.Setup(dc => dc.Submit(It.IsAny<EntityChangeSet>()))
                                                .Callback((EntityChangeSet cs) => 
                                                {
                                                    if (cs.AddedEntities.Count > 0)
                                                        testData.Add(cs.AddedEntities.First());
                                                    else if (cs.RemovedEntities.Count > 0)
                                                        testData.Remove(cs.RemovedEntities.First());
                                                    else
                                                    {
                                                        int index = testData.IndexOf(cs.ModifiedEntities.First());
                                                        ((Epic)testData[index]).Title = ((Epic)cs.ModifiedEntities.First()).Title;
                                                        ((Epic)testData[index]).Description = ((Epic)cs.ModifiedEntities.First()).Description;
                                                    }
                                                })
                                                .Returns((EntityChangeSet cs) => cs.GetChangeSetEntries());
        }

        public void Cleanup()
        {
            this.testData.Clear();
            this.myIdeasVM.Cleanup();
            this.mockDomainClient = null;
        }

        void MyEpics_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
        {
            this.MyIdeasUpdated = true;
        }

        void myIdeasVM_PropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e)
        {
            if (e.PropertyName == "MyIdeasVisibility")
            {
                this.AuthorizationPerformed = true;
            }
        }
        
        public bool MyIdeasUpdated { get; private set; }

        public bool AuthorizationPerformed { get; private set; }
        
        public void SetupTestData(IList<Entity> testEntities)
        {
            testData.AddRange(testEntities);
        }

        public void CreateMyIdeasViewModel()
        {
            this.myIdeasVM = new MyIdeasViewModel(mockDomainClient.Object);
            this.myIdeasVM.PropertyChanged += new System.ComponentModel.PropertyChangedEventHandler(myIdeasVM_PropertyChanged);
            this.myIdeasVM.MyEpics.CollectionChanged += new System.Collections.Specialized.NotifyCollectionChangedEventHandler(MyEpics_CollectionChanged);
        }

        public void AddNewIdea()
        {
            Epic newIdea = (Epic)this.myIdeasVM.MyEpics.AddNew();
            newIdea.Title = "Latest idea";
            newIdea.Description = "This is my latest idea";
            newIdea.RequestedBy = "Dave";
            this.myIdeasVM.MyEpics.CommitNew();
            this.myIdeasVM.SubmitChanges();
            this.modified = true;
        }

        public void UpdateIdea()
        {
            this.modified = true;
        }

        public void DeleteIdea()
        {
            this.modified = true;
        }

        public string VerifyMyIdeas()
        {
            if (modified)
                this.mockDomainClient.Verify(dc => dc.Submit(It.IsAny<EntityChangeSet>()), Times.Once());
            this.mockDomainClient.Verify(dc => dc.Query(It.Is<EntityQuery>(q => q.QueryName == myIdeasVM.DomainContext.GetMyIdeasQuery().QueryName)));
            IList<Epic> epics = testData.Cast<Epic>().OrderBy(e => e.CreationDate).ThenBy(e => e.Title).ToList();
            if (this.myIdeasVM.MyEpics.TotalItemCount != testData.Count)
                return string.Format(CultureInfo.InvariantCulture, "Number of Epics doesn't match. Expected: {0}, Actual: {1}", testData.Count, this.myIdeasVM.MyEpics.Count);
            this.myIdeasVM.MyEpics.MoveCurrentToFirst();
            for (int i = 0; i < testData.Count; i++)
			{
                Epic epic = ((Epic)this.myIdeasVM.MyEpics.CurrentItem);
                if (epics[i].Id != epic.Id)
                    return string.Format(CultureInfo.InvariantCulture, "Id doesn't match. Expected: {0}, Actual: {1}", epics[i].Id, epic.Id);
                if (epics[i].Title != epic.Title)
                    return string.Format(CultureInfo.InvariantCulture, "Title doesn't match. Expected: {0}, Actual: {1}", epics[i].Title, epic.Title);
                if (epics[i].Description != epic.Description)
                    return string.Format(CultureInfo.InvariantCulture, "Description doesn't match. Expected: {0}, Actual: {1}", epics[i].Description, epic.Description);
                if (epics[i].CreationDate != epic.CreationDate)
                    return string.Format(CultureInfo.InvariantCulture, "CreationDate doesn't match. Expected: {0}, Actual: {1}", epics[i].CreationDate, epic.CreationDate);
                this.myIdeasVM.MyEpics.MoveCurrentToNext();
			}
            return "Success";
        }

        public bool VerifyNothingDisplayed()
        {
            this.mockDomainClient.Verify(dc => dc.Query(It.Is<EntityQuery>(q => q.QueryName == myIdeasVM.DomainContext.GetMyIdeasQuery().QueryName)), Times.Never());
            if (this.myIdeasVM.MyEpics.TotalItemCount != 0)
                return false;
            if (this.myIdeasVM.MyIdeasVisibility != Visibility.Collapsed)
                return false;
            return true;
        }
    }
}
